import json
import os
from jinja2 import FileSystemLoader, Environment

from distutils.sysconfig import get_python_lib
from zeus.operation_service.app.proxy.asset import AssetProxy
from zeus.operation_service.app.proxy.host import HostProxy
from zeus.operation_service.app.core.framework.task.task_result.result_generator.health_check.report_generator import ReportGenerator


class NodeHealthCheckGenerator(ReportGenerator):

    def __init__(self, report_path):
        super().__init__(report_path)
        self._node_stat = list()
        self.node_template = "html/NodeHealthCheckTemplate.html"
        self.node_summary_template = "html/NodeSummary.html"
        self.templates_path = os.path.join(get_python_lib(), "zeus", "operation_service", "templates")

    def parse_raw_data(self, raw_data):
        result = dict()

        for asset_id, asset_result_set in raw_data.items():
            for host_name_and_host, asset_result in asset_result_set.items():
                asset_result_by_check_item = dict()
                host_name = host_name_and_host.split("@_@")[0]
                task_host = host_name_and_host.split("@_@")[1]
                asset_result_by_check_item["host_name"] = host_name
                asset_result_by_check_item["host_ip"] = task_host
                asset_result_by_check_item["asset_id"] = asset_id
                asset_result_by_check_item['result'] = asset_result
                if not result.keys().__contains__(task_host):
                    result[task_host] = list()
                result[task_host].append(asset_result_by_check_item)
        return result

    def get_single_node_data(self, asset_result_set):
        health_check_info = list()
        importance_map = {"0": "Very important", "1": "Important", "2": "General"}
        stat_map = {"0": "passing", "1": "notPassed", "2": "notPassed", "3": "notPassed",
                    "4": "executionFailed", "5": "executionTimeout", "990": "skipped"}
        nodeHealthStatistics = {"total": 0, "passing": 0, "notPassed": 0, "executionFailed": 0,
                                "executionTimeout": 0,
                                "skipped": 0}

        for asset_result in asset_result_set:
            asset_id = asset_result['asset_id']
            asset_check_item_result = asset_result['result']
            for check_id, check_item_result_json in asset_check_item_result.items():
                asset = AssetProxy().get_asset_by_asset_id(asset_id)
                asset_name = json.loads(asset.name).get("zh")
                check_item_obj = AssetProxy().get_asset_item_by_item_path(asset_id, check_id)
                check_item_detail = json.loads(check_item_obj.item_detail)

                check_item_result = json.loads(check_item_result_json)[0]
                nodeHealthStatistics[stat_map[str(check_item_result["ErrLevel"])]] += 1
                nodeHealthStatistics["total"] += 1

                health_check_check_item_info = dict()
                health_check_check_item_info['asset_name'] = asset_name
                health_check_check_item_info['taskInfo'] = check_item_detail.get("details").get("detail_zh").get(
                    "@value")
                health_check_check_item_info['checkId'] = check_id
                health_check_check_item_info['status'] = stat_map[str(check_item_result["ErrLevel"])]
                health_check_check_item_info['errLevel'] = check_item_result["ErrLevel"]
                health_check_check_item_info['name'] = check_item_detail.get("description").get("des_zh").get("@value")
                health_check_check_item_info["importance"] = importance_map[
                    check_item_detail.get("importance", {"@value": "1"}).get("@value", "1")]
                health_check_item_err_info = check_item_detail["ErrInfo"]

                if health_check_item_err_info and health_check_item_err_info.get(str(check_item_result['ErrInfo'])):
                    health_check_check_item_info["description"] = health_check_item_err_info.get(
                        check_item_result['ErrInfo']).get(
                        "value_zh").get("@value")
                else:
                    health_check_check_item_info["description"] = check_item_result["ErrInfo"]

                check_item_sug_info = check_item_detail["Suggest"]
                if check_item_sug_info and check_item_sug_info.get(check_item_result["Suggest"]):
                    health_check_check_item_info["suggestion"] = check_item_sug_info.get(
                        check_item_result["Suggest"]).get(
                        "value_zh").get("@value")
                else:
                    health_check_check_item_info["suggestion"] = check_item_result["Suggest"]
                health_check_info.append(health_check_check_item_info)
        sort_map = {0: 3, 1: 1, 2: 1, 3: 1, 4: 2, 5: 2}  # 通过ErrLevel排序
        health_check_info = sorted(health_check_info,
                                   key=lambda e: (sort_map[e.__getitem__('errLevel')], int(e.__getitem__('checkId'))))
        nodeHealthStatistics.update((k, str(v)) for k, v in nodeHealthStatistics.items())
        return health_check_info, nodeHealthStatistics

    def prepare_summary_data(self, host_ip, nodeHealthStatistics):
        node_info_for_summary = dict()
        node_info_for_summary["ip"] = host_ip
        host = HostProxy().get_host_by_ip(host_ip)
        node_info_for_summary["hostName"] = host.get("host_name", "")
        node_info_for_summary.update(nodeHealthStatistics)

        if nodeHealthStatistics["total"] == nodeHealthStatistics["passing"]:
            node_info_for_summary["status"] = "passing"
        elif int(nodeHealthStatistics["passing"]) > 0:
            node_info_for_summary["status"] = "partially.passed"
        elif int(nodeHealthStatistics["notPassed"]) > 0:
            node_info_for_summary["status"] = "not.passed"
        else:
            node_info_for_summary["status"] = "execution.failed"

        self._node_stat.append(node_info_for_summary)

    def get_summary_data(self):
        summary_report_info = dict()
        item_health_statistics = {"total": 0, "passing": 0, "not.passed": 0, "execution.failed": 0,
                                  "partially.passed": 0}
        for node in self._node_stat:
            item_health_statistics[node["status"]] += 1
            item_health_statistics["total"] += 1

        sort_map = {"passing": 3, "partially.passed": 2, "not.passed": 1, "execution.failed": 0}   # 通过status排序
        self._node_stat = sorted(self._node_stat,
                                       key=lambda e: (
                                           sort_map[e.__getitem__('status')], e.__getitem__('ip')))
        return summary_report_info, item_health_statistics

    def generate_report(self, raw_data):
        result = self.parse_raw_data(raw_data)
        loader = FileSystemLoader(self.templates_path)
        env = Environment(loader=loader)
        node_path = os.path.join(self._report_path, "nodes")
        summary_path = self._report_path

        if not os.path.exists(node_path):
            os.makedirs(node_path)

        item_template = env.get_template(self.node_template)
        for host, asset_result_set in result.items():
            health_check_info, nodeHealthStatistics = self.get_single_node_data(asset_result_set)
            self.prepare_summary_data(host, nodeHealthStatistics)
            item_template.stream(resourceBundle=self.get_resource_bundle(), healthcheckInfo=health_check_info,
                                 nodeHealthStatistics=nodeHealthStatistics).dump(f"{node_path}/result_{host}.html")

        summary_report_info, itemHealthStatistics = self.get_summary_data()
        summary_template = env.get_template(self.node_summary_template)
        summary_template.stream(summaryReportInfo=summary_report_info, resourceBundle=self.get_resource_bundle(),
                                nodeInfo=self._node_stat, itemHealthStatistics=itemHealthStatistics).dump(
            f"{summary_path}/Summary.html")
